﻿从状态机视角看，处理器上当前执行的指令及指令所需的数据共同构成了执行流，CPU 执行指令后引起执行流状态的转移。
线程是对 CPU 上的执行流状态的描述，执行流的状态由执行流使用的寄存器及内存空间两个要素唯一确定。
这意味着只需要保存执行流所需的寄存器，确保其使用的空间不发生变动，就可以在任意时刻恢复某个执行流的执行，进而使多个执行流并发成为可能。

用户线程和内核线程是用户态和内核态对执行流不同粒度的逻辑划分。
用户态可以根据程序各模块逻辑的不同将程序切分为若干个用户态的执行流，即用户级线程。
用户级线程的实现局限于用户空间。
例如，在高级语言中，可以使用轮询的方式让若干个函数轮流执行，每个函数都可视作一个单独的执行流，这种对执行流的较细的粒度划分只对用户态可见，操作系统无法感知到用户线程的存在。

内核线程是指在操作系统内核空间维护若干能够刻画某一执行流状态的对象，即线程控制块（Thread Control Block，TCB）。
在状态机模型视角下的计算机中，一个执行流的状态可以由寄存器、该执行流使用的内存这二者完全确定。
时钟中断的驱动下的 CPU 可以在任意时刻打断执行流，只需要在中断前保存该执行流被打断前的状态（中断现场），就可以在任何时刻通过恢复中断现场让执行流重新开始执行，执行流本身则无法感知该过程的发生。
内核线程概念和硬件提供的中断机制的配合，才真正地实现了诸线程之间的切换，即线程调度。
因此，从这个视角看，线程调度的最小单位就是内核线程。

由若干用户线程构成粒度更粗的执行流形成了内核线程，内核线程通过 TCB 描述该执行流的状态。
操作系统内核空间维护一个由 TCB 位基本单元构成的数据结构（如队列），此外还有独立于内核线程的调度器（scheduler）。
当中断发生时，CPU 上正在运行的线程被打断，通过中断描述符定位到调度器的代码段，由调度器负责决定下一次将哪个线程换上 CPU 执行。
调度器决出被调度上 CPU 执行的线程后，紧接着保存当前执行流的状态到其 TCB 中，然后恢复待执行线程的状态。

程序设计视角下，若干个线程共同完成某一项任务，进程就是对任务执行这一概念的抽象。
现代操作系统中的进程是容纳这些线程的容器，除此之外，进程中还保管线程运行所需的内存堆、程序代码等共享资源。

由于进程和线程的这种联系，GNU/Linux 中的进程和线程并没有在实现上做出明确区分，而是采用一种统一的结构 \lstinline{task_struct} 来描述进程和线程 \cite{linux-kernel-doc}。
Windows 将进程和线程视作两类不同的内核对象，线程及其所需共享资源容纳在进程中 \cite{win-internals}。
从高级语言视角看，线程类似于函数，执行线程的过程本质上就是调用一个函数的过程。
每一条线程运行在逻辑 CPU 核心上，逻辑 CPU 核心拥有一套完整的硬件资源，其中就包括堆栈指针寄存器和页目录寄存器。
独立的堆栈指针寄存器意味着线程可以拥有独立的栈帧，进而可以在高级语言中定义作用域局限于当前线程的符号，如 \lstinline{thread_local} 类型的变量。
进程则作为资源管理容器，拥有进程需要共享的全局资源，如内存堆。
当进程中的若干线程分散于不同的逻辑 CPU 核心中执行时，通过设置这些逻辑 CPU 核心的页目录寄存器，就可以使所有的线程共享完全一样的内存空间。
此外，独立的页目录寄存器使得个各个进程拥有独立的物理内存映射方案，在硬件层面做到了进程地址空间的隔离。
不同的进程还可以通过映射相同的物理页面共享同样的物理内存空间，例如，通过映射相同的内核空间，各个进程中的线程可以共用一份操作系统调用的实现代码。
